package cn.pping.user.service.impl;

import cn.pping.basic.constant.BaseConstants;
import cn.pping.basic.exception.BusinessExeption;

import cn.pping.basic.jwt.JwtUtils;
import cn.pping.basic.jwt.RsaUtils;
import cn.pping.basic.util.HttpUtil;
import cn.pping.basic.util.JsonResult;
import cn.pping.basic.util.MD5Utils;
import cn.pping.basic.util.StrUtils;
import cn.pping.org.mapper.EmployeeMapper;
import cn.pping.system.domain.Menu;
import cn.pping.user.constant.WxConstants;
import cn.pping.user.domain.LoginData;
import cn.pping.user.domain.Logininfo;
import cn.pping.user.domain.User;
import cn.pping.user.domain.Wxuser;
import cn.pping.user.dto.LoginDto;
import cn.pping.user.dto.WxDto;
import cn.pping.user.mapper.LogininfoMapper;
import cn.pping.user.mapper.UserMapper;
import cn.pping.user.mapper.WxuserMapper;
import cn.pping.user.service.ILoginService;
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.security.PrivateKey;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author pping
 * @since 2022-07-29
 */
@Service
public class LoginServiceImpl implements ILoginService {
    @Autowired
    private LogininfoMapper logininfoMapper;

    @Autowired
    private WxuserMapper wxuserMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private EmployeeMapper employeeMapper;
    /**
    * @Title: loginSuccessJwtHandler 登录JWT
    * @Description: TODO
    * @Author: Pan
    * @Version: 1.0
    * @Date:  2022/8/6 3:19
    * @Parameters: [logininfo]
    * @Return java.util.Map<java.lang.String,java.lang.Object>
    */
    private Map<String, Object> loginSuccessJwtHandler(Logininfo logininfo) {

        try {
            LoginData loginData = new LoginData();
            loginData.setLogininfo(logininfo);
            Map<String, Object> map = new HashMap<>();
            // 判断登录人是否是管理人员，
            if(logininfo.getType()==0){ // 管理人员
                // 返回当前登录人的权限
                List<String> permissions = employeeMapper.getPermissionsByLogininfoId(logininfo.getId());

                // 当前登录人所有菜单
                List<Menu> menus = employeeMapper.getMenusByLogininfoId(logininfo.getId());

                // 存入loginData
                loginData.setMenus(menus);
                loginData.setPermissions(permissions);

                // 存入map
                map.put("permissions",permissions);
                map.put("menus",menus);
            }

            //  加密
            //4.通过私钥对登录信息进行加密 - jwtToken串
            PrivateKey privateKey = RsaUtils.getPrivateKey(RsaUtils.class.getClassLoader()                                             	  .getResource("auth_rsa.pri").getFile());
            //将登陆人信息加密得到jwtToken串
            String jwtToken = JwtUtils.generateTokenExpireInMinutes(loginData, privateKey, 3000);

            map.put("token",jwtToken);
            map.put("logininfo",logininfo);

            return map;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }


    @Override
    public Map<String, Object> account(LoginDto dto) {
        // 根据手机号和tpye查询 没有查询到用户信息
        Logininfo logininfo = logininfoMapper.getLogininfoByDto(dto);
        if (logininfo == null) {
            throw new BusinessExeption("账号或密码错误！");
        }
        // 判断账户密码是否错误
        // 获取后端的账户密码
        String md5 = MD5Utils.encrypByMd5(logininfo.getSalt() + dto.getPassword());
        if (!md5.equals(logininfo.getPassword())) {
            throw new BusinessExeption("账号或密码错误！");
        }

        // 没有问题后将数值放进redis中
        // 随机生成一个key（token）
//        String token = UUID.randomUUID().toString();
//        redisTemplate.opsForValue().set(token, logininfo, 30, TimeUnit.MINUTES);
//        HashMap<String, Object> map = new HashMap<>();
//        map.put("token", token);
//        // 把盐值，和密码设置为null
//        logininfo.setSalt(null);
//        logininfo.setPassword(null);
//        map.put("logininfo", logininfo);
        Map<String,Object> map = loginSuccessJwtHandler(logininfo);

        return map;
    }

    /**
     * @Title: weChat
     * @Description: TODO
     * @Author: Pan
     * @Version: 1.0
     * @Date: 2022/8/1 15:04
     * @Parameters: [code]
     * @Return cn.pping.basic.util.JsonResult
     */

    @Override
    public JsonResult weChat(String code) {
        /**
         * 登录分析：
         * 已经绑定过：根据用户的Code授权码查询openID和token码
         * 如果查的到就是已经绑定直接方向登录
         *
         * 没有绑定过就后台没有数据 就生成一条新的数据绑定
         *
         */
        // 根据Code查询 给微信平台发送请求 获取信息
        // 调用工具类发送请求 返回一个json格式的对象
        String jsonObj = HttpUtil.httpGet(WxConstants.GET_ACK_URL
                .replace("APPID", WxConstants.APPID)
                .replace("SECRET", WxConstants.SECRET)
                .replace("CODE", code));
        // 字符串转换为json格式对象
        JSONObject jsonObject = JSONObject.parseObject(jsonObj);
        String access_token = jsonObject.getString("access_token");
        String openid = jsonObject.getString("openid");
        // 根据返回的opendi查询User
        Wxuser dbUser = wxuserMapper.loadByOpenId(openid);
        // 判断是否登录过和是否绑定过
        if (dbUser != null && dbUser.getUser_id() != null) {
            // 已经登录过了，直接免密登录
            // 通过信息获取logininfo的信息
            Logininfo logininfo = logininfoMapper.loadByUser(dbUser.getUser_id());
//            System.out.println(logininfo);
//            // 没有问题后将数值放进redis中
//            // 随机生成一个key（token）
//            String token = UUID.randomUUID().toString();
//            redisTemplate.opsForValue().set(token, logininfo, 30, TimeUnit.MINUTES);
//            HashMap<String, Object> map = new HashMap<>();
//            map.put("token", token);
//            // 把盐值，和密码设置为null
//            logininfo.setSalt(null);
//            logininfo.setPassword(null);
//            map.put("logininfo", logininfo);
            Map<String,Object> map = loginSuccessJwtHandler(logininfo);

            return JsonResult.me().setResultObj(map);
            //oa9wA01E7JweNRKasIsck1Tk_clo
        } else {
            // 如果没有就返回重新绑定页面 拼接一个token和openid给前端
            String param = "?accessToken=" + access_token + "&openId=" + openid;
            return JsonResult.me().setMsg("绑定").setResultObj(param);
        }
    }

    @Override
    public JsonResult binder(WxDto wxdto) {
        // 获取用户传过来的数据
        String phone = wxdto.getPhone();
        String verifyCode = wxdto.getVerifyCode();
        String openId = wxdto.getOpenId();
        String accessToken = wxdto.getAccessToken();

        // 非空校验
        if (StringUtils.isEmpty(phone)
                || StringUtils.isEmpty(verifyCode)
                || StringUtils.isEmpty(openId)
                || StringUtils.isEmpty(accessToken)) {
            throw new BusinessExeption("参数不能为空");
        }
        // 校验验证码
        Object redisObj = redisTemplate.opsForValue().get(phone + BaseConstants.VerifyCodeConstan.WXBINDER);
        if (redisObj == null) {
            throw new BusinessExeption("验证码过期，请重新获取！");
        }
        if (!verifyCode.equalsIgnoreCase(redisObj.toString().split(":")[0])) {
            throw new BusinessExeption("验证码输入错误，请重新输入！");
        }

        // 根据openID拿到用户数据 发送第三次请求
        String jsonObj = HttpUtil.httpGet(WxConstants.GET_USER_URL
                .replace("ACCESS_TOKEN", accessToken)
                .replace("OPENID", openId)
        );

        // 拿到用户请求后保存给微信数据表
        Wxuser dbWxUser = jsonObj2WxUser(jsonObj);

        // 根据电话好嘛查询user中的电话号码看是否已经注册
        User dbUser = userMapper.findByPhone(phone);
        // 数据库没有
        if (dbUser == null) {
            // wxuser to user
            dbUser = wxUser2User(phone);
            // user to logininfo
            Logininfo logininfo = user2Logininfo(dbUser);
            // 保存logininfo(返回自增的主键)
            logininfoMapper.add(logininfo);
            dbUser.setLogininfoId(logininfo.getId());
            userMapper.add(dbUser);
        }
        // 把user的id字段关联给微信的Userid
        dbWxUser.setUser_id(dbUser.getId());
        // 在微信用户信息中添加user
        wxuserMapper.add(dbWxUser);

        // 通过电话查询Logininfo
        Logininfo logininfo = logininfoMapper.loadById(dbUser.getLogininfoId());
        // 免密登录。
//        String token = UUID.randomUUID().toString();
//        // 设置三十分钟过去
//        redisTemplate.opsForValue().set(token, logininfo, 30, TimeUnit.MINUTES);
//
//        // 准备一个map
//        HashMap<String, Object> map = new HashMap<>();
//
//        map.put("token", token);
//        // 把盐值，和密码设置为null
//        logininfo.setSalt(null);
//        logininfo.setPassword(null);
//        map.put("logininfo", logininfo);
        Map<String,Object> map = loginSuccessJwtHandler(logininfo);
        // controller
        return JsonResult.me().setResultObj(map);

    }

    private Logininfo user2Logininfo(User dbUser) {
        Logininfo logininfo = new Logininfo();
        logininfo.setType(1);
        BeanUtils.copyProperties(dbUser, logininfo);
        return logininfo;
    }

    private User wxUser2User(String phone) {
        User user = new User();
        user.setUsername(phone);
        user.setPhone(phone);
        // 生成一个颜值， 密码
        String salt = StrUtils.getComplexRandomString(32);
        user.setSalt(salt);

        // 生一个密码
        String password = StrUtils.getComplexRandomString(6);

        // 加密
        String dbPassword = MD5Utils.encrypByMd5(salt + password);
        user.setPassword(dbPassword);

        return user;
    }


    private Wxuser jsonObj2WxUser(String jsonObj) {
        JSONObject jsonObject = JSONObject.parseObject(jsonObj);
        Wxuser wxuser = new Wxuser();
        wxuser.setAddress(jsonObject.getString("city"));
        wxuser.setHeadimgurl(jsonObject.getString("headimgurl"));
        wxuser.setNickname("xx"); // 昵称，特使字符
        wxuser.setOpenid(jsonObject.getString("openid"));
        wxuser.setSex(jsonObject.getInteger("sex"));
        wxuser.setUnionid(jsonObject.getString("unionid"));
        return wxuser;
    }

}
